#ifndef _NTH_LIB_H
#include <nth-lib.h>
#endif

#ifndef _STDIO_H
#include <stdio.h>
#endif

#ifndef _STRING_H
#include <string.h>
#endif

/* Prototypes begin here */

int Find_Largest_String_Length(
	char ** string_array,
	size_t string_count,
	size_t * largest_length
);

/* Definitions begin here. */

int Clean_Nth_Plugin(
	struct Nth_Plugin * nth_plugin
){
	if (!nth_plugin){
		return NTH_ERROR_NULL_POINTER;
	}

	if (nth_plugin->plugin_name){
		free(nth_plugin->plugin_name);
		nth_plugin->plugin_name = 0;
	}

	if (nth_plugin->plugin_description){
		free(nth_plugin->plugin_description);
		nth_plugin->plugin_description = 0;
	}

	return 0;
}

int Find_Largest_String_Length(
	char ** string_array,
	size_t string_count,
	size_t * largest_length
){
	size_t string_index = 0;
	size_t string_length = 0;

	if (!string_array){
		return NTH_ERROR_NULL_POINTER;
	}

	if (!largest_length){
		return NTH_ERROR_NULL_POINTER;
	}

	(*largest_length) = 0;

	while (string_index < string_count){

		if (!string_array[string_index]){
			string_index++;
			continue;
		}

		string_length = strlen(string_array[string_index]);

		if (string_length > (*largest_length)){
			(*largest_length) = string_length;
		}

		string_index++;
	}

	return 0;
}

int Initialize_Nth_Plugin(
	struct Nth_Plugin * nth_plugin
){
	char plugin_name[] = "help";
	char plugin_desc[] = "Get help with this program";

	if (!nth_plugin){
		return NTH_ERROR_NULL_POINTER;
	}

	nth_plugin->plugin_name = malloc(sizeof(plugin_name));

	if (!nth_plugin->plugin_name){
		return NTH_ERROR_NO_MEMORY;
	}

	memcpy(
		nth_plugin->plugin_name,
		plugin_name,
		sizeof(plugin_name)
	);

	nth_plugin->plugin_description = malloc(sizeof(plugin_desc));

	if (!nth_plugin->plugin_description){
		free(nth_plugin->plugin_name);
		nth_plugin->plugin_name = 0;
		return NTH_ERROR_NO_MEMORY;
	}

	memcpy(
		nth_plugin->plugin_description,
		plugin_desc,
		sizeof(plugin_desc)
	);

	nth_plugin->plugin_callback = Nth_Plugin_Callback;

	return 0;
}

int Nth_Plugin_Callback(
	struct Nth_Program * nth_program,
	struct Nth_Number * plugin_number
){
	int error = 0;

	struct Nth_Plugin * plugin_array = 0;
	size_t plugin_index = 0;
	size_t plugin_count = 0;

	char * plugin_name = 0;
	char * plugin_description = 0;

	char * fallback_name = "(null)";
	char * fallback_description = "(null)";

	char ** name_array = 0;
	size_t name_count = 0;

	size_t largest_name_length = 0;
	size_t current_name_length = 0;
	size_t name_diff_length = 0;

	if (!nth_program){
		return NTH_ERROR_NULL_POINTER;
	}

	name_count = nth_program->plugin_count;
	name_array = malloc(name_count * sizeof(char *));

	if (!name_array){
		return NTH_ERROR_NO_MEMORY;
	}

	plugin_index = 0;
	plugin_count = nth_program->plugin_count;
	plugin_array = nth_program->plugin_array;

	while (plugin_index < plugin_count){
		name_array[plugin_index] = plugin_array[plugin_index].plugin_name;
		plugin_index++;
	}

	error = Find_Largest_String_Length(
		name_array,
		name_count,
		&largest_name_length
	);

	if (error){

		Push_Nth_Failure(
			nth_program,
			"Nth_Plugin_Callback",
			"Failed to find largest plugin name"
		);

		free(name_array);
		return NTH_ERROR_UNSPECIFIED;
	}

	free(name_array);
	name_array = 0;
	name_count = 0;

	fputc('\n', stdout);

	fprintf(stdout, "Available commands:");

	fputc('\n', stdout);

	plugin_index = 0;
	plugin_count = nth_program->plugin_count;
	plugin_array = nth_program->plugin_array;

	while (plugin_index < plugin_count){

		plugin_name = plugin_array[plugin_index].plugin_name;

		if (!plugin_name){
			plugin_name = fallback_name;
		}

		plugin_description = plugin_array[plugin_index].plugin_description;

		if (!plugin_description){
			plugin_description = fallback_description;
		}

		if (!plugin_array[plugin_index].plugin_description){
			plugin_description = fallback_description;
		}

		current_name_length = strlen(plugin_name);

		name_diff_length = 0;
		name_diff_length += largest_name_length;
		name_diff_length -= current_name_length;

		fprintf(
			stdout,
			"\t%s:%*s%s\n",
			plugin_name,
			(int) name_diff_length + 1,
			" ",
			plugin_description
		);

		plugin_index++;
	}

	fputc('\n', stdout);

	return 0;
}

